package com.google.zxing.client.android;

import android.graphics.Bitmap;
import android.util.Log;

import com.google.zxing.ResultPoint;
import com.google.zxing.qrcode.detector.FinderPattern;

import java.util.Vector;

/**
 * Created by yanmaoshen on 2017/11/17.
 */
public class CheckSpecialZone {

    private static final String TAG = "CheckSpecialZone";
    private static final int CENTER_QUORUM = 2;
    protected static final int MIN_SKIP = 3; // 1 pixel/module times 3 modules/center
    protected static final int MAX_MODULES = 57; // support up to version 10 for mobile clients


    private boolean hasSkipped;
//    private final int[] crossCheckStateCount;
    private Bitmap m_image = null;
    private Vector<ResultPoint> m_posVec = new Vector<ResultPoint>();

    public CheckSpecialZone(Bitmap img) {
        m_image = img;
        m_posVec.clear();

        long start = System.currentTimeMillis();
        imgBinary();
        long end = System.currentTimeMillis();
        Log.d(TAG, "CheckSpecialZone imgBinary in " + (end - start) + " ms");

        start = end;
        getSpecialPoint();
        end = System.currentTimeMillis();
        Log.d(TAG, "CheckSpecialZone getSpecialPoint in " + (end - start) + " ms");
    }

    private void imgBinary(){//}, int width, int height, int wInterval){
        if (m_image == null){
            Log.e(TAG, "CheckSpecialZone image error");
            return;
        }
        final int optionNum = 4;
//    Bitmap selectImg = img.createBitmap(img, 36, 230,
//            Math.min(364, img.getWidth()-36),
//            Math.min(40, img.getHeight()-230) );//按照指定区域创建位图
        int w = m_image.getWidth();
        int h = m_image.getHeight();
        Vector<Integer> sumVec = new Vector<Integer>();
        for (int i = 0; i < optionNum; i++) {
            sumVec.add(0);
        }

        int sumNum[] = {0,0,0,0};
        for (int i = 0; i < h; i++) {
            for (int j = 0; j < w; j++) {
                int p = m_image.getPixel(j, i);
                // 分离三原色
                int red = ((p & 0x00FF0000) >> 16);
                int green = ((p & 0x0000FF00) >> 8);
                int blue = (p & 0x000000FF);
                if(red==green && red == blue){
                    m_image.setPixel(j, i,
                            (red > 128) ? 0xFFFFFFFF : 0xFF000000);
                }else {
                    double gray = 0.30 * red + 0.59 * green + 0.11 * blue;
                    m_image.setPixel(j, i,
                            (gray > 128.0f) ? 0xFFFFFFFF : 0xFF000000);
                }
            }
        }

    }

    private void getSpecialPoint() {
        if (m_image == null){
            Log.e(TAG, "CheckSpecialZone image error");
            return;
        }
        int w = m_image.getWidth();
        int h = m_image.getHeight();

        for (int i = 0; i < h; i++) { //0-300
            for (int j = 0; j < w; j++) { // 400-h
                if (m_image.getPixel(j,i)==0xFF000000 && checkSpecialByState(j, i)){
                    m_posVec.add(new ResultPoint(j, i));
                    Log.d(TAG, "CaptureActivity posVec: " + j + " " + i);
                }
            }
        }

    }

    private boolean checkSpecialByState(int x, int y){
        if (m_image == null){
            Log.e(TAG, "CheckSpecialZone image error");
            return false;
        }
/*        boolean tryHarder = true;
//    boolean pureBarcode = hints != null && hints.containsKey(DecodeHintType.PURE_BARCODE);
        boolean pureBarcode = false;
        int maxI = m_image.getHeight();
        int maxJ = m_image.getWidth();
        // We are looking for black/white/black/white/black modules in
        // 1:1:3:1:1 ratio; this tracks the number of such modules seen so far

        // Let's assume that the maximum version QR Code we support takes up 1/4 the height of the
        // image, and then account for the center being 3 modules in size. This gives the smallest
        // number of pixels the center could be, so skip this often. When trying harder, look for all
        // QR versions regardless of how dense they are.
        int iSkip = (3 * maxI) / (4 * MAX_MODULES);
        if (iSkip < MIN_SKIP || tryHarder) {
            iSkip = MIN_SKIP;
        }
//    iSkip = 16;
        boolean done = false;
        int[] stateCount = new int[5];
        for (int i = iSkip - 1; i < maxI && !done; i += iSkip) {

            // Get a row of black/white values
//      System.out.printf("iSkip = %d\n",iSkip);
            stateCount[0] = 0;
            stateCount[1] = 0;
            stateCount[2] = 0;
            stateCount[3] = 0;
            stateCount[4] = 0;
            int currentState = 0;
            for (int j = 0; j < maxJ; j++) {
                if (m_image.getPixel(j, i) == 0xFF000000) {
                    // Black pixel
                    if ((currentState & 1) == 1) { // Counting white pixels
                        currentState++;
                    }
                    stateCount[currentState]++;
                } else { // White pixel
                    if ((currentState & 1) == 0) { // Counting black pixels
                        if (currentState == 4) { // A winner?
                            if (foundPatternCross(stateCount)) { // Yes
                                System.out.printf("i=%d,j=%d,iSkip=%s,found !\n",i,j,iSkip);
                                boolean confirmed = handlePossibleCenter(stateCount, i, j, pureBarcode);
                                if (confirmed) {
                                    System.out.printf("i=%d,j=%d,iSkip=%s,confirmed !\n",i,j,iSkip);
                                    // Start examining every other line. Checking each line turned out to be too
                                    // expensive and didn't improve performance.
                                    iSkip = 2;
                                    if (hasSkipped) {
                                        done = haveMultiplyConfirmedCenters();
                                    } else {
                                        int rowSkip = findRowSkip();
                                        System.out.printf("rowSkip = %d\n", rowSkip);
                                        if (rowSkip > (stateCount[0]+stateCount[1])) {
                                            // Skip rows between row of lower confirmed center
                                            // and top of presumed third confirmed center
                                            // but back up a bit to get a full chance of detecting
                                            // it, entire width of center of finder pattern

                                            // Skip by rowSkip, but back off by stateCount[2] (size of last center
                                            // of pattern we saw) to be conservative, and also back off by iSkip which
                                            // is about to be re-added
                                            i += rowSkip - (stateCount[0]+stateCount[1]) - iSkip;
                                            j = maxJ - 1;
                                        }
                                    }
                                } else {
                                    stateCount[0] = stateCount[2];
                                    stateCount[1] = stateCount[3];
                                    stateCount[2] = stateCount[4];
                                    stateCount[3] = 1;
                                    stateCount[4] = 0;
                                    currentState = 3;
                                    continue;
                                }
                                // Clear state to start looking again
                                currentState = 0;
                                stateCount[0] = 0;
                                stateCount[1] = 0;
                                stateCount[2] = 0;
                                stateCount[3] = 0;
                                stateCount[4] = 0;
                            } else { // No, shift counts back by two
                                stateCount[0] = stateCount[2];
                                stateCount[1] = stateCount[3];
                                stateCount[2] = stateCount[4];
                                stateCount[3] = 1;
                                stateCount[4] = 0;
                                currentState = 3;
                            }
                        } else {
                            stateCount[++currentState]++;
                        }
                    } else { // Counting white pixels
                        stateCount[currentState]++;
                    }
                }
            }
            if (foundPatternCross(stateCount)) {
                boolean confirmed = handlePossibleCenter(stateCount, i, maxJ, pureBarcode);
                if (confirmed) {
                    System.out.printf("i=%d,j=%d,iSkip=%s,confirmed !\n",i,maxJ,iSkip);
                    iSkip = stateCount[0];
                    if (hasSkipped) {
                        // Found a third one
                        done = haveMultiplyConfirmedCenters();
                    }
                }
            }
        }

        FinderPattern[] patternInfo = selectBestPatterns();

        System.out.printf("patternInfo is %d\n",patternInfo.length);
        OneKeyPatternFinder.orderBestPatterns(patternInfo);
        System.out.printf("patternInfo is %d\n",patternInfo.length);
        return new OneKeyFinderPatternInfo(patternInfo);
*/

        return false;
    }


    private boolean checkSpecial(int x, int y){
        // 11311 22622  33933    44 12 44
        float ratio = 0.9f;
        int speical_1[] = {
                0xFF000000, 0xFFFFFFFF,
                0xFF000000, 0xFF000000, 0xFF000000,
                0xFFFFFFFF, 0xFF000000,};
        int speical_2[] = {
                0xFF000000, 0xFF000000, 0xFFFFFFFF,0xFFFFFFFF,
                0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000,
                0xFFFFFFFF, 0xFFFFFFFF,0xFF000000, 0xFF000000,};
        int speical_3[] = {
                0xFF000000, 0xFF000000, 0xFF000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
                0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000,0xFF000000,0xFF000000,
                0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFF000000, 0xFF000000,0xFF000000};
        int speical_4[] = {
                0xFF000000, 0xFF000000,0xFF000000,0xFF000000, 0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,
                0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000,
                0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000, 0xFF000000,
                0xFFFFFFFF, 0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFF000000, 0xFF000000,0xFF000000,0xFF000000,};
        Vector<int[]> specialVec = new Vector<int[]>();
//    specialVec.add(speical_1);
        specialVec.add(speical_2);
//    specialVec.add(speical_3);
//    specialVec.add(speical_4);

        int width = m_image.getWidth();
        int height = m_image.getHeight();

        for (int j=0; j<specialVec.size(); j++) {
            int isSpecialNum = 0;
            int[] sp = specialVec.get(j);
            int length = sp.length;
            int needLength = (int)(length*ratio);
            int start = x - length / 2;
            for (int i = start; i < start+length; i++) {
                if (i<0){
                    continue;
                }
                if (i>=width){
                    break;
                }
                int pixel = m_image.getPixel(i,y);
                int special = sp[i-start];
                if (pixel == special){
//        if (img.getPixel(i, y) != specialVec.get(j)[i]) {
                    isSpecialNum ++;
                }
            }
            if (isSpecialNum < needLength) {
                continue;
            }

            isSpecialNum = 0;
            start = y - length / 2;
            for (int i = start; i < start+length; i++) {
                if (i<0){
                    continue;
                }
                if (i>=height){
                    break;
                }
                int pixel = m_image.getPixel(x,i);
                int special = sp[i-start];
                if (pixel == special){
//        if (img.getPixel(x, i) != specialVec.get(j)[i]) {
                    isSpecialNum ++;
                }
            }
            if (isSpecialNum >= needLength) {
                return true;
            }
        }
        return false;
    }

    public Vector<ResultPoint> getPosVec() {
        return m_posVec;
    }

    public void setPosVec(Vector<ResultPoint> posVec) {
        this.m_posVec = posVec;
    }
}
